class ChordDiagram
   
  # Attributes
  attr_reader :mfc_class_name
  attr_reader :mfc_class_schema

  attr_reader :top_fret
  attr_accessor :chord_name
  
  # Constants 
  DEFAULT_TOP_FRET = 0
   
  MIN_TOP_FRET = 0
  MAX_TOP_FRET = 20
   
  MIN_FRET_NUMBER = 0
  MAX_FRET_NUMBER = 24
        
  STRING_MUTED = 0x000000fe
  NOT_USED = 0x000000ff
        
  # Constructor  
  def initialize(chord_name = nil, top_fret = nil, fret_number1 = nil, fret_number2 = nil, fret_number3 = nil, fret_number4 = nil, fret_number5 = nil, fret_number6 = nil, fret_number7 = nil)

    mfc_class_name = "CChordDiagram"
    mfc_class_schema = 1

    @top_fret = DEFAULT_TOP_FRET
    @fret_number_array = [ ]
    @chord_name = ChordName.new
    
    return false unless valid_top_fret?(top_fret)
    chord_name=(chord_name)
    add_fret_numbers(fret_number1, fret_number2, fret_number3, fret_number4, fret_number5, fret_number6, fret_number7)

  end
  
  # Methods   
  def valid_top_fret?(top_fret)
    return (top_fret <= MAX_TOP_FRET)
  end
   
  def top_fret=(top_fret)
    return false unless valid_top_fret?(top_fret)
    @top_fret = top_fret
    return true
  end
   
  def valid_string?(string)
    return (string < string_count())
  end
   
  def string_count()
    return @fret_number_array.count
  end
   
  def valid_fret_number?(fret_number)
    return ((fret_number <= MAX_FRET_NUMBER) || (fret_number == STRING_MUTED) || (fret_number == NOT_USED))
  end
   
  def delete_fret_number_array_contents
    @fret_number_array = [ ]
  end
   
  def chord_diagram=(chord_name, top_fret, fret_number1, fret_number2, fret_number3, fret_number4, fret_number5, fret_number6, fret_number7)
    chord_name=(chord_name)
    return false unless top_fret=(top_fret)
    return AddFretNumbers($fret_number1, $fret_number2, $fret_number3, $fret_number4, $fret_number5, $fret_number6, $fret_number7)
  end
   
  def fret_number=(string, fret_number)
    return false unless valid_string?(string)
    return false unless valid_fret_number?(fret_number)
    @fret_number_array[string] = fret_number
    return true
  end

  def fret_number(string)
    return false unless valid_string?(string)
    return (@fret_number_array[string])
  end
   
  def add_fret_numbers(fret_number1, fret_number2, fret_number3, fret_number4, fret_number5, fret_number6, fret_number7)
    return false unless valid_fret_number(fret_number1)
    return false unless valid_fret_number(fret_number2)
    return false unless valid_fret_number(fret_number3)
    return false unless valid_fret_number(fret_number4)
    return false unless valid_fret_number(fret_number5)
    return false unless valid_fret_number(fret_number6)
    return false unless valid_fret_number(fret_number7)
     
    delete_fret_number_array_contents
     
    @fret_number_array << fret_number1
    @fret_number_array << fret_number2
    @fret_number_array << fret_number3     
    if (fret_number4 == NOT_USED) return true
    @fret_number_array << fret_number4
    if (fret_number5 == NOT_USED) return true
    @fret_number_array << fret_number5
    if (fret_number6 == NOT_USED) return true
    @fret_number_array << fret_number6
    if (fret_number7 == NOT_USED) return true
    @fret_number_array << fret_number7
     
    return true
  end
   
  def same_voicing?(chord_diagram)
    this_string_count = string_count
    other_string_count = chord_diagram.string_count
     
    if (this_string_count != other_string_count)
      return false
    end

    this_string_count.times do |i|
      if (@fret_number_array[i] != chord_diagram.fret_number_array[i])
        return false
      end
    end
     
    return true
  end
   
  def same_voicing_frets?(fret_number1, fret_number2, fret_number3, fret_number4 = NOT_USED, fret_number5 = NOT_USED, fret_number6 = NOT_USED, fret_number7 = NOT_USED)
    temp = ChordDiagram.new
    temp.add_fret_numbers(fret_number1, fret_number2, fret_number3, fret_number4, fret_number5, fret_number6, fret_number7)
    return same_voicing?(temp)
  end
   
  def spelling
    return_value = ""
     
    string_count.downto(1) do |i|
      fret_number = ""
      if (@fret_number_array[i-1] == STRING_MUTED)
        return_value .= "x"
      else
        fret_number = sprintf("%d", @fret_number_array[i - 1])
      end
      return_value .= $fret_number
       
      if (i > 1) return_value .= " "
    end
     
    return return_value
  end
    
  # Serialization
  def do_serialize(stream)
    @chord_name.do_serialize(stream)
    write_byte(stream, @top_fret)
    write_byte(stream, string_count)
    string_count.times do |i|
      write_byte(stream, @fret_number_array[i])
    end
    return true
  end
   
  def do_deserialize(stream)
    @chord_name = ChordName.new
    @chord_name.do_deserialize(stream)
    @top_fret = read_byte(stream)
    count = read_byte(stream)
    count.times do |i|
      fret_number = read_byte(stream)
      @fret_number_array << fret_number
    end
    return true
  end

end
